<template>
  <div class="container">
    <h1>JSON转C#实体类</h1>
    <div class="converter-container">
      <div class="input-section">
        <h3>JSON输入</h3>
        <el-input
          v-model="jsonInput"
          type="textarea"
          :rows="10"
          placeholder="请输入JSON数据"
          @input="handleJsonInput"
        />
        <div class="options">
          <el-checkbox v-model="options.useProperties" label="使用属性">使用属性</el-checkbox>
          <el-checkbox v-model="options.useDataAnnotations" label="使用数据注解">使用数据注解</el-checkbox>
          <el-checkbox v-model="options.useNullable" label="使用可空类型">使用可空类型</el-checkbox>
        </div>
        <el-button type="primary" @click="convertToCSharp" :disabled="!isValidJson">转换</el-button>
      </div>
      <div class="output-section">
        <h3>C#类</h3>
        <el-input
          v-model="csharpOutput"
          type="textarea"
          :rows="10"
          readonly
        />
        <el-button type="primary" @click="copyOutput" :disabled="!csharpOutput">复制代码</el-button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'
import { ElMessage } from 'element-plus'

const jsonInput = ref('')
const csharpOutput = ref('')
const isValidJson = ref(false)

const options = reactive({
  useProperties: true,
  useDataAnnotations: true,
  useNullable: true
})

const handleJsonInput = (value) => {
  try {
    if (value) {
      JSON.parse(value)
      isValidJson.value = true
    } else {
      isValidJson.value = false
    }
  } catch (e) {
    isValidJson.value = false
  }
}

const convertToCSharp = () => {
  try {
    const jsonObj = JSON.parse(jsonInput.value)
    const className = 'RootObject'
    const result = generateCSharpClass(jsonObj, className)
    csharpOutput.value = result
  } catch (e) {
    ElMessage.error('JSON解析失败，请检查输入格式')
  }
}

const generateCSharpClass = (obj, className) => {
  let result = ''
  if (options.useDataAnnotations) {
    result += 'using System.ComponentModel.DataAnnotations;\n'
  }
  result += 'using System;\n\nnamespace JsonConverter\n{\n'
  result += generateClass(obj, className, 1)
  result += '}'
  return result
}

const generateClass = (obj, className, indent) => {
  const indentStr = '    '.repeat(indent)
  let result = `${indentStr}public class ${className}\n${indentStr}{\n`

  for (const [key, value] of Object.entries(obj)) {
    const propertyName = toPascalCase(key)
    const propertyType = getCSharpType(value)

    if (options.useDataAnnotations) {
      result += `${indentStr}    [JsonProperty("${key}")]\n`
    }
    
    if (options.useProperties) {
      result += `${indentStr}    public ${propertyType} ${propertyName} { get; set; }`
    } else {
      result += `${indentStr}    public ${propertyType} ${propertyName};`
    }
    result += '\n'
  }

  result += `${indentStr}}\n`
  return result
}

const getCSharpType = (value) => {
  if (value === null) {
    return options.useNullable ? 'object?' : 'object'
  }

  switch (typeof value) {
    case 'string':
      return options.useNullable ? 'string?' : 'string'
    case 'number':
      return Number.isInteger(value) 
        ? (options.useNullable ? 'int?' : 'int')
        : (options.useNullable ? 'double?' : 'double')
    case 'boolean':
      return options.useNullable ? 'bool?' : 'bool'
    case 'object':
      if (Array.isArray(value)) {
        const elementType = value.length > 0 ? getCSharpType(value[0]) : 'object'
        return `List<${elementType}>`
      }
      return toPascalCase(Object.prototype.toString.call(value))
    default:
      return 'object'
  }
}

const toPascalCase = (str) => {
  return str.charAt(0).toUpperCase() + str.slice(1)
}

const copyOutput = async () => {
  try {
    await navigator.clipboard.writeText(csharpOutput.value)
    ElMessage.success('代码已复制到剪贴板')
  } catch (err) {
    ElMessage.error('复制失败')
  }
}
</script>

<style scoped>
.container {
  padding: 20px;
}

.converter-container {
  display: flex;
  gap: 20px;
  margin-top: 20px;
}

.input-section,
.output-section {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.options {
  display: flex;
  gap: 20px;
  margin: 10px 0;
}

h1 {
  margin-bottom: 20px;
  color: #409EFF;
}

h3 {
  margin-bottom: 10px;
  color: #606266;
}
</style>